#pragma once 
#include <pthread.h>
#include <iostream>
#include <queue>

namespace cp_queue{
  const int default_cap = 3;
  template<class T>
    class queue{
      private:
        std::queue<T> q;
        int cap_;
        pthread_mutex_t mtx_;
        pthread_cond_t isfull_;
        pthread_cond_t isempty_;
        
        bool IsFull(){//队列是否为满
          return q.size() == cap_;
        }
        bool IsEmpty(){//队列是否为空
          return q.size() == 0;
        }
        void LockQueue(){//给队列加锁
          pthread_mutex_lock(&mtx_);
        }
        void UnLockQueue(){//给队列解锁
          pthread_mutex_unlock(&mtx_);
        }
        void ProducterWait(){//生产者等待
          pthread_cond_wait(&isempty_, &mtx_);
        }
        void ConsumerWait(){//消费者等待
          pthread_cond_wait(&isfull_, &mtx_);
        }
        void WakeProducter(){//唤醒生产者
          pthread_cond_signal(&isempty_);
        }
        void WakeConsumer(){//唤醒消费者
          pthread_cond_signal(&isfull_);
        }
      public:
        queue(int cap = default_cap) : cap_(cap){
          pthread_mutex_init(&mtx_, nullptr);
          pthread_cond_init(&isfull_, nullptr);
          pthread_cond_init(&isempty_, nullptr);
        }
        ~queue(){
          pthread_mutex_destroy(&mtx_);
          pthread_cond_destroy(&isfull_);
          pthread_cond_destroy(&isempty_);
        }
        void push(const T& in){
          LockQueue();//消费者和生产者具有互斥关系，故需要加锁
          
          while(IsFull()){
            ProducterWait();//消费者和生产者具有同步关系，故需要条件等待
          }
          q.push(in);

          UnLockQueue();
          WakeConsumer();
        }
        void pop(T *out){
          LockQueue();//消费者和生产者具有互斥关系，故需要加锁

          while(IsEmpty()){
            ConsumerWait();//消费者和生产者具有同步关系，故需要条件等待
          }
          *out = q.front();
          q.pop();

          UnLockQueue();
          WakeProducter();
        }
    };
}
